package com.slofzx.nuoda.evaluation.version.builder;

import com.alibaba.fastjson.JSONObject;
import com.deepoove.poi.render.compute.EnvModel;
import com.deepoove.poi.render.compute.ReadMapAccessor;
import com.deepoove.poi.render.compute.RenderDataCompute;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义spEl运算处理器
 * 根据系统导出报告，部分规则SpEL不兼容使用使用默认方式获取值
 */
public class CustomSpELRenderDataCompute implements RenderDataCompute {

    private final ExpressionParser parser;
    private final EvaluationContext context;
    private EvaluationContext envContext;
    private boolean isStrict;

    public CustomSpELRenderDataCompute(EnvModel model) {
        this(model, true);
    }

    public CustomSpELRenderDataCompute(EnvModel model, boolean isStrict) {
        this(model, isStrict, Collections.emptyMap());
    }

    public CustomSpELRenderDataCompute(EnvModel model, boolean isStrict, Map<String, Method> spELFunction) {
        this.isStrict = isStrict;
        this.parser = new SpelExpressionParser(new SpelParserConfiguration(null, null, false, false, 2147483647));
        if (null != model.getEnv() && !model.getEnv().isEmpty()) {
            this.envContext = new StandardEvaluationContext(model.getEnv());
            ((StandardEvaluationContext) envContext).addPropertyAccessor(new ReadMapAccessor());
        }
        this.context = new StandardEvaluationContext(model.getRoot());
        ((StandardEvaluationContext) context).addPropertyAccessor(new ReadMapAccessor());
        spELFunction.forEach(((StandardEvaluationContext) context)::registerFunction);
    }

    @Override
    public Object compute(String el) {
        try {
            // 导出报告中key有带冒号的，这里需要特殊处理，同时报告中sqlEl表达式三元运算会失效
            if (el.contains(":")) {
                if (el.contains(".")) {
                    return getSubValueObject(el);
                }
                return getObject(el);
            }
            final SpelExpression expression = (SpelExpression)parser.parseExpression(el);
           // expression.compileExpression();
            if (null != envContext && !el.contains("#this")) {
                try {
                    Object val = expression.getValue(envContext);
                    if (null != val) {
                        return val;
                    }
                } catch (Exception e) {
                    // ignore
                    return getObject(el);
                }
            }
            try {
                return expression.getValue(context);
            } catch (EvaluationException e) {
                return getObject(el);
            }
        } catch (Exception e) {
            if (isStrict) throw e;
            return null;
        }
    }

    /**
     * 直接从上下文中获取所需要的数据
     * @param el
     * @return
     */
    private Object getObject(String el) {
        final HashMap value = (HashMap) this.context.getRootObject().getValue();
        return value.get(el);
    }
    /**
     * 直接从上下文中获取所需要的数据
     * @param el
     * @return
     */
    private Object getSubValueObject(String el) {
        final HashMap value = (HashMap) this.context.getRootObject().getValue();
        String [] split = el.split("\\.");
        final JSONObject sumData = (JSONObject)value.get(split[0]);
        return sumData.get(split[1]);
    }

}